package com.ilikesoup.instant.inclusion;

import com.google.common.collect.Lists;

import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;

public class Inclusions {

    public static <T> Predicate<T> predicate(T... includes) {
        return predicate(new Inclusion<>(Lists.newArrayList(includes), Collections.emptyList(), Inclusion.Mode.INCLUDE), Objects::equals);
    }

    public static <T, V> Predicate<V> predicate(BiPredicate<T, V> tester, T... includes) {
        return predicate(new Inclusion<>(Lists.newArrayList(includes), Collections.emptyList(), Inclusion.Mode.INCLUDE), tester);
    }

    public static <T> Predicate<T> predicateExclude(T... excludes) {
        return predicate(new Inclusion<>(Collections.emptyList(), Lists.newArrayList(excludes), Inclusion.Mode.EXCLUDE), Objects::equals);
    }

    public static <T, V> Predicate<V> predicateExclude(BiPredicate<T, V> tester, T... excludes) {
        return predicate(new Inclusion<>(Collections.emptyList(), Lists.newArrayList(excludes), Inclusion.Mode.EXCLUDE), tester);
    }

    public static <T, V> Predicate<V> predicate(Collection<T> includes, Collection<T> excludes, Inclusion.Mode mode, BiPredicate<T, V> tester) {
        return predicate(of(includes, excludes, mode), tester);
    }

    public static <T, V> Predicate<V> predicate(Inclusion<T> inclusion, BiPredicate<T, V> tester) {
        return obj -> inclusion.isIncluded(obj, tester);
    }

    public static <T> Inclusion<T> of(Collection<T> includes, Collection<T> excludes, Inclusion.Mode mode) {
        return new Inclusion<>(includes, excludes, mode);
    }

    public static <T> Inclusion<T> include(Collection<T> includes) {
        Inclusion<T> inclusion = new Inclusion<>();
        inclusion.addIncludes(includes);
        return inclusion;
    }

    public static <T> Inclusion<T> include(T... includes) {
        Inclusion<T> inclusion = new Inclusion<>();
        inclusion.addIncludes(includes);
        return inclusion;
    }

    public static <T> Inclusion<T> exclude(Collection<T> excludes) {
        Inclusion<T> inclusion = new Inclusion<>();
        inclusion.addExcludes(excludes);
        return inclusion;
    }

    public static <T> Inclusion<T> exclude(T... includes) {
        Inclusion<T> inclusion = new Inclusion<>(Inclusion.Mode.EXCLUDE);
        inclusion.addExcludes(includes);
        return inclusion;
    }


}
